﻿namespace Foggy.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Speech.Synthesis;
    using System.Text;
    using System.Threading;

    using Caliburn.Micro;

    using Foggy.Data;
    using Foggy.Data.Extensions;
    using Foggy.Users;

    using NLog;

    using LogManager = NLog.LogManager;

    /// <summary>
    /// Main view model
    /// </summary>
    public class MainViewModel : Screen
    {
        /// <summary>
        /// The logger instance
        /// </summary>
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        /// <summary>
        /// The FogBugz repository
        /// </summary>
        private readonly IFogBugzRepository fogBugzRepository;

        /// <summary>
        /// The user collection
        /// </summary>
        private IObservableCollection<UserViewModel> users;

        /// <summary>
        /// The user email collection
        /// </summary>
        private IList<string> userEmails;

        /// <summary>
        /// User update timer
        /// </summary>
        private Timer userUpdateTimer;

        /// <summary>
        /// Reminder timer
        /// </summary>
        private Timer reminderTimer;

        /// <summary>
        /// The speaker
        /// </summary>
        private SpeechSynthesizer speaker;

        /// <summary>
        /// Initializes a new instance of the <see cref="MainViewModel" /> class.
        /// </summary>
        /// <param name="fogBugzRepository">The fog bugz repository.</param>
        /// <param name="userService">The user service.</param>
        public MainViewModel(IFogBugzRepository fogBugzRepository, IUserService userService)
        {
            this.UserService = userService;
            this.fogBugzRepository = fogBugzRepository;
        }

        /// <summary>
        /// Gets or sets the user service.
        /// </summary>
        /// <value>
        /// The user service.
        /// </value>
        public IUserService UserService { get; set; }

        /// <summary>
        /// Gets or sets the users.
        /// </summary>
        /// <value>
        /// The users.
        /// </value>
        public IObservableCollection<UserViewModel> Users
        {
            get
            {
                return this.users;
            }

            set
            {
                this.users = value;
                this.NotifyOfPropertyChange(() => this.Users);
            }
        }

        /// <summary>
        /// Called when activating.
        /// </summary>
        protected override void OnActivate()
        {
            base.OnActivate();

            var currentUsers = this.UserService.GetUsers();
            this.userEmails = currentUsers.Select(u => u.Email).ToList();

            var userDictionary = this.fogBugzRepository.GetUsers(this.userEmails);
            var userViewModels = userDictionary.Select(u => new UserViewModel { User = u.Value });
            this.Users = new BindableCollection<UserViewModel>(userViewModels);

            this.speaker = new SpeechSynthesizer { Rate = 1, Volume = 100 };            

            this.DoUpdateUsers(null);

            this.StartUpdateUsers();
            this.StartReminder();
        }

        /// <summary>
        /// Starts the reminder.
        /// </summary>
        private void StartReminder()
        {
            var interval = TimeSpan.FromSeconds(300);
            this.reminderTimer = new Timer(this.DoReminder, null, TimeSpan.Zero, interval);
        }

        /// <summary>
        /// Starts the update users.
        /// </summary>
        private void StartUpdateUsers()
        {
            var interval = TimeSpan.FromSeconds(5 /*120*/);
            this.userUpdateTimer = new Timer(this.DoUpdateUsers, null, interval, interval);
        }

        private void DoReminder(object state)
        {
            if (this.Users == null || this.Users.Count() == 0)
            {
                return;
            }

            foreach (var userViewModel in this.Users)
            {
                var user = userViewModel.User;

                if (user.IsAway)
                {
                    continue;
                }

                var userMessages = new List<string>();

                if (!user.IsCurrentlyWorking)
                {
                    userMessages.Add(string.Format("{0} is currently not tracking time!", user.Name));
                }
                
                if (user.IsOverTimeEstimate)
                {
                    if (user.PercentageOverTimeEstimate.HasValue && user.PercentageOverTimeEstimate > 5)
                    {
                        var message = string.Format(
                            "{0} is currently {1}% over his current estimate", user.Name, (int)Math.Round(user.PercentageOverTimeEstimate.Value));

                        if (user.CurrentIssue.CurrentEstimate.HasValue)
                        {
                            message += string.Format(
                                " of {0}", user.CurrentIssue.CurrentEstimate.Value.ToDisplayString());
                        }

                        userMessages.Add(message);
                    }
                }
                
                if (userMessages.Count > 0)
                {
                    try
                    {
                        foreach (var message in userMessages)
                        {
                            this.speaker.Speak(message);
                        }
                    }
                    catch (Exception exception)
                    {
                        Logger.ErrorException("There was an error speaking", exception);
                    }
                }
            }
        }
       
        private void DoUpdateUsers(object state)
        {
            this.fogBugzRepository.UpdateUsers(this.Users.Select(uvm => uvm.User));            
        }
    }
}